/////////////////////////////////////////////////////////////////////////////
// 
// Project   : Web Content Management JavaScript Library (WCM)
//
// FileName  : wcm.js
// FileType  : JavaScript
// Created   : June 2007
// Version   : 10gR4 (10.1.4.0.0)
//
// Comments  : 
//
// Copyright : Oracle, Incorporated Confidential and Proprietary
//
//             This computer program contains valuable, confidential and proprietary
//             information. Disclosure, use, or reproduction without the written
//             authorization of Oracle is prohibited. This unpublished
//             work by Oracle is protected by the laws of the United States
//             and other countries. If publication of the computer program should occur,
//             the following notice shall apply:
//
//             Copyright (c) 2007, 2008, Oracle.  All rights reserved.
//
/////////////////////////////////////////////////////////////////////////////

var WCM = WCM || {}; // namespace object

//***************************************************************************

WCM.Counter = 0; 

//***************************************************************************
//***************************************************************************
//************************** ENVIRONMENT VARIABLES **************************
//***************************************************************************
//***************************************************************************

WCM.IS_OPERA = (navigator.userAgent.toLowerCase().indexOf("opera") > -1);
WCM.IS_CHROME = (navigator.userAgent.toLowerCase().indexOf("chrome") > -1);
WCM.IS_FIREFOX = (navigator.userAgent.toLowerCase().indexOf("gecko") > -1) && (navigator.userAgent.toLowerCase().indexOf("firefox") > -1);
WCM.IS_NETSCAPE = (navigator.userAgent.toLowerCase().indexOf("gecko") > -1) && (navigator.userAgent.toLowerCase().indexOf("netscape") > -1);
WCM.IS_SAFARI = (((navigator.userAgent.toLowerCase().indexOf("applewebkit") > -1) || (navigator.userAgent.toLowerCase().indexOf("apple") > -1)) && !WCM.IS_CHROME);
WCM.IS_IE = (navigator.userAgent.toLowerCase().indexOf("msie") > -1) && !WCM.IS_OPERA;
WCM.IS_MOZILLA = (navigator.userAgent.toLowerCase().indexOf("mozilla") > -1) && !WCM.IS_IE && !WCM.IS_OPERA && !WCM.IS_FIREFOX && !WCM.IS_NETSCAPE;

WCM.IS_WINDOWS = (navigator.platform.toLowerCase().indexOf('win') > -1);
WCM.IS_MAC = (navigator.platform.toLowerCase().indexOf('mac') > -1);
WCM.IS_LINUX = (navigator.platform.toLowerCase().indexOf('linux') > -1);

WCM.IS_STRICT = (document.compatMode == 'CSS1Compat');
WCM.IS_QUIRKS = (document.compatMode == 'BackCompat');

WCM.HAS_DOM_IMPLEMENTATION_LEVEL1 = document.implementation && document.implementation.hasFeature;
WCM.HAS_DOM_IMPLEMENTATION_LEVEL2 = document.implementation && document.implementation.createDocument;
WCM.HAS_DOM_XPATH_LEVEL3 = WCM.HAS_DOM_IMPLEMENTATION_LEVEL1 && document.implementation.hasFeature("XPath", "3.0");

//***************************************************************************
//***************************************************************************
//************************ JAVASCRIPT TYPE UTILITIES ************************
//***************************************************************************
//***************************************************************************

WCM.IsString = function(obj) { return (typeof obj == 'string'); }
WCM.IsNumber = function(obj) { return (typeof obj == 'number'); }
WCM.IsBoolean = function(obj) { return (typeof obj == 'boolean'); }
WCM.IsArray = function(obj) { return (obj instanceof Array); }
WCM.IsFunction = function(obj) { return (typeof obj == 'function'); }
WCM.IsObject = function(obj) { return (typeof obj == 'object'); }
WCM.IsUndefined = function(obj) { return (typeof obj == 'undefined'); }
WCM.IsNull = function(obj) { return (obj == null); }
WCM.IsNotNull = function(obj) { return (obj != null); }
WCM.IsNotValid = function(obj) { return (WCM.IsNull(obj) || WCM.IsUndefined(obj)); }
WCM.IsValid = function(obj) { return (!WCM.IsNull(obj) && !WCM.IsUndefined(obj)); }

WCM.ToBool = function(obj, def)
{
	if (WCM.IsValid(obj))
	{
		return ((obj == 1) || (obj == true) || (obj == "1") || (obj.toString().toLowerCase() == "true") || (obj.toString().toLowerCase() == 'yes'));
	}

	return (WCM.IsBoolean(def) ? def : false);
};

WCM.ToInt = function(obj, def)
{
	if (WCM.IsValid(obj))
	{
		var x = parseInt(obj);
		if (!isNaN(x))
		{
			return x;
		}
	}

	return (WCM.IsNumber(def) ? def : 0);
}

WCM.ToString = function(obj, def, allowEmpty)
{
	allowEmpty = WCM.ToBool(allowEmpty, true);

	if (WCM.IsValid(obj))
	{
		return (obj.toString() === '' && !allowEmpty) ? def : obj.toString();
	}

	return (WCM.IsString(def) ? def : '');
}

WCM.ToFloat = function(obj, def)
{
	if (WCM.IsValid(obj))
	{
		var x = parseFloat(obj);
		if (!isNaN(x))
		{
			return x;
		}
	}

	return (WCM.IsNumber(def) ? def : 0.0);
}

WCM.ToArray = function(obj)
{
	if (WCM.IsValid(obj) && WCM.IsArray(obj))
	{
		return obj
	}
	else if(WCM.IsValid(obj))
	{
		return [obj];
	}	
	else
	{
		return [];
	}
}

WCM.ToCollection = function(obj)
{
	if (WCM.IsValid(obj) && obj.length && obj[0])
	{
		return obj
	}
	else
	{
		return WCM.ToArray(obj);
	}	
}

WCM.GetLengthUnits = function(str)
{
	if (WCM.IsValid(str))
	{
		str = WCM.ToString(str).Trim();

		// Skip any digits (or number characters)
		var i = 0;
		for (i = 0; i < str.length; i++)
		{
			if ("-.0123456789 ".indexOf(str.charAt(i)) == -1)
			{
				break;
			}
		}

		var units = str.substring(i);
		if (units.length == 0)
		{
			units = 'px';
		}

		return units.toLowerCase();
	}

	return '';
}

//***************************************************************************
//***************************************************************************
//************************ X-BROWSER IMPLEMENTATIONS ************************
//***************************************************************************
//***************************************************************************

//
// x-browser way to create a blank XML DOM Document
//
if (WCM.HAS_DOM_IMPLEMENTATION_LEVEL2)
{
    WCM.CreateXMLDocument = function() { return document.implementation.createDocument("", "", null); }
}
else if (WCM.IS_IE)
{
    WCM.CreateXMLDocument = function() { return new ActiveXObject("Msxml2.DOMDocument"); }
}

//***************************************************************************

//
// if NodeType enumeration doesn't exist, then provide it
//
if(!window.Node || !window.Node.ELEMENT_NODE)
{
    window.Node = {ELEMENT_NODE: 1, ATTRIBUTE_NODE: 2, TEXT_NODE: 3, CDATA_SECTION_NODE: 4, ENTITY_REFERENCE_NODE: 5,  ENTITY_NODE: 6, PROCESSING_INSTRUCTION_NODE: 7, COMMENT_NODE: 8, DOCUMENT_NODE: 9, DOCUMENT_TYPE_NODE: 10, DOCUMENT_FRAGMENT_NODE: 11, NOTATION_NODE: 12};
};

//***************************************************************************

//
// if XMLHttpRequest is not implemented, but this is IE, then provide our own XMLHttpRequest using MSXML
//
if (!window.XMLHttpRequest && WCM.IS_IE)
{
    window.XMLHttpRequest = function() { return new ActiveXObject("Msxml2.XMLHTTP"); }
}

//***************************************************************************

//
// if XMLSerializer is not implemented, but I can create a DOM Document that has an .xml property, then provide our own XMLSerializer
//
if (!window.XMLSerializer && WCM.CreateXMLDocument && ("xml" in WCM.CreateXMLDocument()))
{
    window.XMLSerializer = function(){};
    window.XMLSerializer.prototype.serializeToString = function(oNode) { return oNode.xml; };
}

//***************************************************************************

//
// if DOMParser does not exist, but I can create a DOM Document that has a .loadXML method, then provide our own DOMParser
//
if (!window.DOMParser && WCM.CreateXMLDocument && ("loadXML" in WCM.CreateXMLDocument()))
{
    window.DOMParser = function() {};
    window.DOMParser.prototype.parseFromString = function(xml, contentType)
    {
	   var doc = WCM.CreateXMLDocument();
	   doc.resolveExternals = false;
	   doc.loadXML(xml);

	   // Some versions of the MSXML parser (namely MSXML3) will use zero-based
	   // indexing for its xpath expressions (contrary to the xpath spec) unless
	   // you set the "SelectionLanguage" to "XPath".  For example the expression:
	   //     foo[1]
	   // would actually return the second foo element instead of the first.
		if( "setProperty" in doc )
		{
			doc.setProperty( "SelectionLanguage", "XPath" );
		}

	   return doc;
    }
}

//***************************************************************************

//
// provide our own Node.selectNodes() method if necessary
//
if (WCM.CreateXMLDocument && ("selectNodes" in WCM.CreateXMLDocument()))
{
    WCM.HAS_SELECT_NODES = true; // most likely IE
}
else if (WCM.HAS_DOM_XPATH_LEVEL3)
{
    WCM.HAS_SELECT_NODES = true; // most likely MOZILLA

    XMLDocument.prototype.selectNodes = Node.prototype.selectNodes = function(expr)
    {
	   var doc = (this.ownerDocument ? this.ownerDocument : this);
	   var nsResolver = doc._namespaces ? function(prefix) { return doc._namespaces[prefix]; } 
									   : doc.createNSResolver(doc.documentElement);

	   var nodes = doc.evaluate(expr, this, nsResolver, XPathResult.ORDERED_NODE_ITERATOR_TYPE, null);

	   var nodelist = new Array();
	   while ((node = nodes.iterateNext()) != null) { nodelist.push(node); }
	   return nodelist;
    }

    XMLDocument.prototype.selectSingleNode = Node.prototype.selectSingleNode = function(expr)
    {
	   var nodeList = this.selectNodes("(" + expr + ")[1]"); // only need the first matching node (xpath uses 1-based offsets)
	   if (nodeList.length > 0)
		  return nodeList[0];
	   else
		  return null;
    }
}
else
{
    WCM.HAS_SELECT_NODES = false;
}

//***************************************************************************

WCM.SetXPathNamespaces = function(dom, ns)
{
	if (WCM.IS_IE)
	{
		dom.setProperty("SelectionLanguage", "XPath");
		dom.setProperty("SelectionNamespaces", ns);
	}
	else
	{
		// store all prefix:uri pairs in an array in the DOM object for use during .selectSingleNode / .selectNodes() methods
		var namespaces = ns.indexOf(" ") > -1 ? ns.split(" ") : new Array(ns);
		dom._namespaces = new Array(namespaces.length);
		for (var i = 0 ; i < namespaces.length ; i++)
		{
			var thisNamespace = namespaces[i];
			var colonPos = thisNamespace.indexOf(":");
			var assignPos = thisNamespace.indexOf("=");
			if (colonPos == 5 && assignPos > colonPos+2)
			{
				var prefix = thisNamespace.substring(colonPos+1, assignPos);
				var uri = thisNamespace.substring(assignPos+2, thisNamespace.length-1);
				dom._namespaces[prefix] = uri;
			}
		}
	}
}


//***************************************************************************

WCM.CBCache = {};

//***************************************************************************

WCM.AddCBCacheObject = function(obj, objId)
{
	objId = objId || WCM.GetId(obj);
	WCM.CBCache[objId] = obj;
	return objId;
};

//***************************************************************************

WCM.GetCBCacheObject = function(objId)
{
	try
	{
		return WCM.CBCache[objId];
	}
	catch(e)
	{
		return null;
	}
};

//***************************************************************************

WCM.$CB = function()
{
	var cb = new Object();

	var argStart = 0;
	if (typeof(arguments[0]) == 'object')
	{
		cb.obj = arguments[0];
		cb.func = arguments[1];
		argStart = 2;
	}
	else if (typeof(arguments[0]) == 'function')
	{
		cb.obj = null;
		cb.func = arguments[0];
		argStart= 1;	
	}
	else
	{
		throw "usage $CB(func, arg0, arg1) or $CB(obj, func, arg0, arg1)";
	}

	cb.args = new Array();
	for(var n = argStart ; n < arguments.length ; n++)
		cb.args.push(arguments[n]);
	
	cb.id = WCM.GenerateUniqueId('$CB');
	return WCM.$CB_2(WCM.AddCBCacheObject(cb));
};

//***************************************************************************

WCM.$CB_2 = function(cbId)
{
	return function() 
	{
		var cb = WCM.GetCBCacheObject(cbId);
		if (cb)
		{
			var args = [];
			for (var n = 0; n < cb.args.length; n++)
				args.push(cb.args[n]);

			for(n = arguments.length - 1; n >= 0; n--)
				if (!(n===0 && arguments[n] && (WCM.IsValid(arguments[n].cancelBubble) || 
				   (WCM.IsValid(arguments[n].stopPropagation) && WCM.IsValid(arguments[n].preventDefault)))))			
					args.unshift(arguments[n]);

			return cb.func.apply(cb.obj, args); 
		}
		return null;
	};
};

//***************************************************************************
// shorthand
window.$CB = WCM.$CB;

//***************************************************************************

//
// Special case for use in DHTML event handling (e.g. obj.onclick = $CBE() ) that
// takes into account the fact that on W3C browsers the event object is the 1st 
// parameter, but in IE the event object is not passed at all.
//

WCM.$CBE = function()
{
	var cb = new Object();

	var argStart = 0;
	if (typeof(arguments[0]) == 'object')
	{
		cb.obj = arguments[0];
		cb.func = arguments[1];
		argStart = 2;
	}
	else if (typeof(arguments[0]) == 'function')
	{
		cb.obj = null;
		cb.func = arguments[0];
		argStart= 1;	
	}
	else
	{
		throw "usage $CBE(func, arg0, arg1) or $CBE(obj, func, arg0, arg1)";
	}

	cb.args = new Array();
	for(var n = argStart ; n < arguments.length ; n++)
		cb.args.push(arguments[n]);

	cb.id = WCM.GenerateUniqueId('$CBE');
	return WCM.$CBE_2(WCM.AddCBCacheObject(cb));
};

//***************************************************************************

WCM.$CBE_2 = function(cbId)
{
	return function() 
	{
		var cb = WCM.GetCBCacheObject(cbId);
		if (cb)
		{
			var args = [];
			for (var n = 0; n < cb.args.length; n++)
				args.push(cb.args[n]);

			for(n = arguments.length - 1 ; n >= 0 ; n--)
				args.unshift(arguments[n]);

			if (WCM.IS_IE && window.event && (!args[0] || !args[0].srcElement))
				args.unshift(window.event);

			return cb.func.apply(cb.obj, args); 
		}
		return null;
	}
}

//***************************************************************************

// shorthand
window.$CBE = WCM.$CBE;

//
// setTimeout in Firefox browsers pass a single param to the callback, but not in
// other browsers. This makes it tricky to use our $CB() class for passing additional
// params to the callback in x-browser mechanism.... So, lets provide setTimeoutEx()
// which works same in all browsers...
//

window.setTimeoutEx = function(callback, time)
{
	if (WCM.IS_FIREFOX)
	{
		return setTimeout($CB(WCM.TimerFF, callback), time);
	}
	else
	{
		return setTimeout($CB(WCM.Timer, callback), time);
	}
}

//***************************************************************************

window.setIntervalEx = function(callback, time)
{
	if (WCM.IS_FIREFOX)
	{
		return setInterval($CB(WCM.TimerFF, callback), time);
	}
	else
	{
		return setInterval($CB(WCM.Timer, callback), time);
	}
}

//***************************************************************************

WCM.TimerFF = function(clearTimeoutId, cb)
{
	cb();
};

//***************************************************************************

WCM.Timer = function(cb)
{
	cb();
};

//***************************************************************************
//***************************************************************************
//***************************** STRING METHODS ******************************
//***************************************************************************
//***************************************************************************

String.prototype.StripCharacters = function(badchars)
{
	 return this.replace(new RegExp(RegExp.escape(badchars), 'gi'), '');
}

//***************************************************************************

String.prototype.FindOneOf = function(str)
{
    for (var i = 0 ; i < str.length ; i++)
    {
	   var pos = this.indexOf(str.charAt(i));
	   if (pos > -1)
		  return pos;
    }
    return -1;
}

//***************************************************************************

String.prototype.ReplaceAll = function(expr, replacement, opts)
{
	if (WCM.IsString(expr) && WCM.IsString(replacement))
	{
		opts = (WCM.IsString(opts) ? opts : 'gi');
		return this.replace(new RegExp(expr, opts), replacement);
	}
	return this;
}

//***************************************************************************

String.prototype.CompareNoCase = function(str2)
{
    return (WCM.IsString(str2) && (this.toLowerCase() == str2.toLowerCase()));
}

//***************************************************************************

String.prototype.Trim = function()
{
    return this.replace(/^\s*/, '').replace(/\s*$/, ''); 
}

//***************************************************************************

WCM.ENTITY_AMP  = '&amp;';
WCM.ENTITY_LT   = '&lt;';
WCM.ENTITY_GT   = '&gt;';
WCM.ENTITY_QUOT = '&quot;';
WCM.ENTITY_APOS = '&#39;';   // IE doesnt support &apos;

//***************************************************************************

String.prototype.EntityEncode = function()
{
	return this.replace(/&/ig, WCM.ENTITY_AMP)
			.replace(/</ig, WCM.ENTITY_LT)
			.replace(/>/ig, WCM.ENTITY_GT)
			.replace(/"/ig, WCM.ENTITY_QUOT)
				.replace(/'/ig, WCM.ENTITY_APOS);
}

//***************************************************************************

String.prototype.EntityDecode = function()
{
	return this.replace(new RegExp(WCM.ENTITY_APOS, 'ig'),  '\'')
					.replace(new RegExp(WCM.ENTITY_QUOT, 'ig'), '"')
					.replace(new RegExp(WCM.ENTITY_GT, 'ig'),   '>')
					.replace(new RegExp(WCM.ENTITY_LT, 'ig'),   '<')
					.replace(new RegExp(WCM.ENTITY_AMP, 'ig'),  '&');
}

//***************************************************************************

String.prototype.ContainsMatch = function(expr, options)
{
	return (null != this.match(new RegExp(expr, WCM.ToString(options, 'ig'))));
}

//***************************************************************************

String.prototype.ReturnMatch = function(expr, options)
{
	this.match(new RegExp(expr, WCM.ToString(options, 'ig')));
	return RegExp.$1;
}

//***************************************************************************
//***************************************************************************
//***************************** ARRAY METHODS *******************************
//***************************************************************************
//***************************************************************************

if (!Array.prototype.indexOf)
{
	Array.prototype.indexOf = function (obj, fromIndex)
	{
		if ( WCM.IsNotValid( fromIndex ) )
		{
			fromIndex = 0;
		}
		else if (fromIndex < 0)
		{
			fromIndex = Math.max(0, this.length + fromIndex);
		}
		for (var i = fromIndex; i < this.length; i++)
		{
			if (this[i] === obj)
			{
				return i;
			}
		}
		return -1;
	};
}

//***************************************************************************

Array.Create = function(n)
{
	if (n && (n instanceof Array))
		return n
	else if (n)
		return [n];
	else
		return [];
}

//***************************************************************************

Array.prototype.PushIfNotNull = function(x) 
{ 
	if (WCM.IsValid(x)) 
	{
		this.push(x); 
	}
	return this;
}

//***************************************************************************

Array.prototype.RemoveAt = function(index)
{
	return this.slice(0, index).concat(this.slice(index+1));
} 

//***************************************************************************

Array.prototype.Find = function(name)
{
	for(var n = 0 ; n < this.length ; n++)
		if (this[n] == name)
			return n;

	return -1;	
}

//***************************************************************************

Array.prototype.AddNameValuePair = function(name, value)
{
	if( !WCM.IsValid( this[name] ) )
		this.push(name);

	this[name] = value;
}

//***************************************************************************

Array.prototype.GetNameValuePairByIndex = function(n) 
{ 
	return this[this[n]]; 
}


//***************************************************************************

Array.prototype.MergeNameValuePairs = function(array, preferNewValues)
{
	var preferNew = WCM.ToBool(preferNewValues);

	for(var n = 0 ; n < array.length ; n++)
	{
		var name = array[n];
		var value = array[name];

		if(!preferNew)
		{
			if (this.Find(name) < 0)
			{
				this.push(name);
				this[name] = value;
			}
		}
		else	
		{
			this.AddNameValuePair(name, value);
		}		
	}
}

//***************************************************************************
//***************************************************************************
//***************************** REGEX METHODS *******************************
//***************************************************************************
//***************************************************************************

RegExp.escape = function(text) 
{
	if (!arguments.callee.sRE) 
	{
		var specials = [
			'../default.htm', '.', '*', '+', '?', '|',
			'(', ')', '[', ']', '{', '}', '\\'
			];
		arguments.callee.sRE = new RegExp('(\\' + specials.join('|\\') + ')', 'g');
	}
	return text.replace(arguments.callee.sRE, '\\$1');
}

//***************************************************************************
//***************************************************************************
//**************** URL, QUERY STRING & COOKIE UTILITY METHODS ***************
//***************************************************************************
//***************************************************************************

WCM.GetUrl = function(context)
{
	return (context || window).location.href.toString();
}

//***************************************************************************

WCM.GetUrlServer = function(context)
{
	return (context || window).location.protocol + '../..//' + (context || window).location.host;
}

//***************************************************************************

WCM.GetUrlBase = function(context)
{
	context = WCM.IsString(context) ? context : (context || window).location.href;
	return context.split("?")[0].split("#")[0];
}

//***************************************************************************

WCM.GetUrlBaseMinusFile = function(context)
{
	return WCM.GetUrlBase(context).substring(0, WCM.GetUrlBase(context).lastIndexOf('/'));
}

//***************************************************************************

WCM.GetUrlFileName = function(context)
{
	return WCM.GetUrlBase(context).substring(WCM.GetUrlBase(context).lastIndexOf('/')+1);
}

//***************************************************************************

WCM.GetBookmark = function(context)
{
	context = WCM.IsString(context) ? context : (context || window).location.href;
	return (WCM.IsString(context.split("#")[1])) ? "#"+context.split("#")[1] : "";
}

//***************************************************************************

WCM.GetQueryString = function(context)
{
	return WCM.IsString(context) ? ((context.split('?')[1] && '?'+context.split('?')[1].split('#')[0]) || '') : (context || window).location.search;
}

//***************************************************************************

WCM.GetQueryStringValue = function(name, query)
{
	query = WCM.GetQueryString(query);

	if (query.indexOf(name) >= 0)
	{
		var q = query.replace(/.*\?/, '');

		if (WCM.IsValid(q) && q.length > 0)
		{
			var pairs = q.split("&");
			for (var i = 0; i < pairs.length; i++)
			{
				var p = pairs[i].split("=");
				if (name == p[0])
					return decodeURIComponent(p[1]);
			}
		}
	}
	return null;
}

//***************************************************************************

WCM.SetQueryStringValue = function(name, value, query)
{
	query = WCM.GetQueryString(query);
	var q = WCM.RemoveQueryStringValue(name, query);
	var con = (q.length == 0) ? "?" : (q[q.length-1] == "&") ? "" : "&";
	return q + con + name + "=" + encodeURIComponent(value);
}

//***************************************************************************

WCM.RemoveQueryStringValue = function(name, query)
{
	query = WCM.GetQueryString(query);

	if (query.indexOf(name) >= 0)
	{
		var q = query.replace(/\?/,'');

		if (WCM.IsValid(q) && q.length > 0)
		{
			var tmp = "";
			var pairs = q.split("&");
			for (var i = 0; i < pairs.length; i++)
			{
				var p = pairs[i].split("=");
				if (name != p[0])
					tmp += "&" + p[0] + "=" + p[1];
			}
			return tmp.replace(/\&/,'?');
		}
	}
	return query;
}

//***************************************************************************

WCM.SetCookie = function(name, value, days)
{
	var expires = null;
	if (days)
	{
		var date = new Date();
		date.setTime(date.getTime()+(days*24*60*60*1000));
		expires = "; expires=" + date.toGMTString();
	}
	else
		expires = "";

	document.cookie = name+"="+value+expires+"; path=/";
}

//***************************************************************************

WCM.GetCookie = function(name)
{
	var nameEQ = name + "=";
	var ca = document.cookie.split(';');

	for(var i=0;i < ca.length;i++)
	{
		var c = ca[i];
		while (c.charAt(0)==' ')
			c = c.substring(1,c.length);

		if (c.indexOf(nameEQ) == 0)
			return c.substring(nameEQ.length,c.length);
	}
	return null;
}

//***************************************************************************

WCM.RemoveCookie = function(name)
{
    WCM.SetCookie(name, "", -1);
}

//***************************************************************************

WCM.ReloadURL = function(url, context)
{
	context = context || window;
	url = url || WCM.GetUrl(context);

	if (context.location.href.toString() != url)
		context.location = url;
	else
		context.location.reload(true);
}

//***************************************************************************
//***************************************************************************
//***************************** UTILITY METHODS *****************************
//***************************************************************************
//***************************************************************************

WCM.ContextualEval = function(s)
{
	return eval(s);
}
var wcm_eval = WCM.ContextualEval;

//***************************************************************************

WCM.Base = function()
{
	this.inheritanceCount = 0;
};

//***************************************************************************

WCM.Object = function(o)
{
	WCM.Object.F.prototype = o;
	var me = new WCM.Object.F();
		
	if (WCM.IsNumber(me.inheritanceCount) && WCM.IsFunction(me.Init))
	{
		me['Init_' + (me.inheritanceCount++)] = me.Init;
	}

	me.Initialize = WCM.Object.Initialize;
	return me;
};

//***************************************************************************

WCM.Object.Initialize = function(options, me)
{
	for (var n=0; n<me.inheritanceCount; n++)
	{
		me['Init_' + n].apply(me, [options]);
	}

	if (WCM.IsFunction(me.Init))
	{
		me.Init.apply(me, [options]);
	}
};

//***************************************************************************

WCM.Object.F = function() { };

//***************************************************************************

WCM.Escape = function(sXml)
{
    if (sXml)
    {
	   return sXml.replace(/&/g, "&amp;")
			    .replace(/</g, "&lt;")
				.replace(/>/g, "&gt;")
				.replace(/"/g, "&quot;")
				.replace(/'/g, "&apos;");
    }
    else
    {
	   return "";
    }
}

//***************************************************************************

WCM.Unescape = function(sXml)
{
    if (sXml)
    {
	   return sXml.replace(/&apos;/g,"'")
				.replace(/&quot;/g,"\"")
				.replace(/&gt;/g,">")
				.replace(/&lt;/g,"<")
				.replace(/&amp;/g,"&");
    }
    else
    {
	   return "";
    }
}

//***************************************************************************

WCM.EscapeForPreTag = function(str)
{
	str = WCM.ToString(str, '').replace(/</g, "&lt;").replace(/>/g, "&gt;");
	if (WCM.IS_IE)
	{
		str   = str.replace(/ /g, '&nbsp;')
				 .replace(/\r\n/g, '<br />')
				 .replace(/\n/g, '<br />')
				 .replace(/\t/g, '&nbsp;&nbsp;&nbsp;');
	}

	return str;
};

//***************************************************************************

WCM.Serialize = function(obj)
{
    if (obj)
    {
	   if (obj.innerHTML)
	   {
		  return obj.innerHTML;
	   }
	   else if (XMLSerializer)
	   {
		  return (new XMLSerializer()).serializeToString(obj);
	   }
	   else if (obj.toString)
	   {
		  return obj.toString();
	   }
    }

    return "";
}

//***************************************************************************

WCM.GetPathToScript = function(rx)
{
	var scripts = document.getElementsByTagName('script');
	for (var i = 0 ; i < scripts.length ; i++)
	{
		var fileName = scripts[i].src.split('/');
		fileName = fileName[fileName.length-1];
		if (rx.test(fileName))
		{
			var path = scripts[i].src.substring(0, scripts[i].src.lastIndexOf('/')+1);

			if (!/^(http:|https:|file:)/.test(path.toLowerCase()))
			{
				if (path.charAt(0) == '../default.htm')	// server root based path
					path = WCM.GetUrlServer() + path;
				else
					path = WCM.GetUrlBaseMinusFile() + '/' + path;
			}
			return path;
		}
	}

	return null;
}

//***************************************************************************

WCM.GenerateUniqueId = function(prepend, append)
{
	return (prepend || '') + (''+Math.random()).replace(/\./, '') + (WCM.Counter++) + (append || '');
}

//***************************************************************************

WCM.Wait = function(options)
{
	options = options || {};
	var ccb = options.conditioncallback || WCM.EmptyFunction;  // Return true to continue waiting
	var scb = options.successcallback || WCM.EmptyFunction;  // Called when ccb returns true (when the condition is met)
	var ecb = options.errorcallback || WCM.EmptyFunction;  // Called when the wait period has been exceeded and the condition has not been met
	var interval = options.interval || 100;  // How long to wait before testing the condition 
	var count = options.count || 25;  // How many times to test the condition
	var context = options.context || window;

	var times = 0;
	var timerId = 0;
	
	var params = {ccb: ccb, scb: scb, ecb: ecb, count: count, context: context, times: times, timerId: timerId};
	var paramsId = WCM.AddObject(params);

	params.timerId = context.setIntervalEx($CB(WCM.Wait.Exists, paramsId), interval);
}

//***************************************************************************

WCM.Wait.Exists = function(paramsId)
{
	var params = WCM.GetObject(paramsId);
	if (params)
	{
		if (params.times++ > params.count)
		{
			WCM.RemoveObject(paramsId);
			params.context.clearInterval(params.timerId);
			params.ecb();
			return;
		}

		if (!params.ccb())
		{
			WCM.RemoveObject(paramsId);
			params.context.clearInterval(params.timerId);
			params.scb();
		}
	}
};

//***************************************************************************

WCM.GetString = function(key)
{
	if (!WCM.GetString.stored && WCM.Strings)
	{
		WCM.AddObject({id: 'Strings', res: WCM.Strings});
		WCM.GetString.stored = true;
	}

	var argValues = WCM.GetString.arguments;
	var argCount = argValues.length;
	var value = (WCM.Strings || {})[key];
	if (value == null)
		return key;

	if( argCount > 1 )
	{
		var beginQuote = WCM.Strings["wwBeginQuote"] || "\'";
		var endQuote = WCM.Strings["wwEndQuote"] || "\'";

		for (var i=1; i<argCount; i++)
		{
			var regexp = eval("/{" + i + "[.!}]*}/g");
			value = value.replace(regexp, argValues[i]);
			regexp = eval("/{" + i + "q[.!}]*}/g");
			value = value.replace(regexp, beginQuote + argValues[i] + endQuote);
		}
	}
	return value;
}

//***************************************************************************

WCM.GetTime = function()
{
	var date   = new Date();

	var year   = date.getFullYear();
	var month  = date.getMonth() + 1;
	var day    = date.getDate();

	var hour   = WCM.GetTime.Format(date.getHours(), '0', 2);
	var min    = WCM.GetTime.Format(date.getMinutes(), '0', 2);
	var sec    = WCM.GetTime.Format(date.getSeconds(), '0', 2);
	var mil    = WCM.GetTime.Format(date.getMilliseconds(), '0', 4);

	return (month + '/' + day + '/' + year + '-' + hour + ':' + min + ':' + sec + ':' + mil);
};

//***************************************************************************

WCM.GetTime.Format = function(s, filler, length, before)
{
	s = WCM.ToString(s);
	filler = filler || ' ';
	length = length || 1;
	before = WCM.ToBool(before, true);

	var grow = 0;
	if (grow = (length - s.length))
	{
		for (var n = 0; n < grow; n++)
		{
			s = (before) ? filler + s : s + filler;
		}
	}
	return s;
};

//***************************************************************************

WCM.LoadScriptInline = function(ctxt, path, id)
{
	if (WCM.IsString(path) && WCM.IsValid(ctxt) && WCM.IsValid(ctxt.document))
	{
		id = id || '';
		ctxt.document.write('<scr' + 'ipt id="' + id + '" type="text/javascript" src="' + path + '"><\/scr' + 'ipt>');
	}
}

WCM.WriteScriptInline = function(ctxt, jsScript, id)
{
	if (WCM.IsString(jsScript) && WCM.IsValid(ctxt) && WCM.IsValid(ctxt.document))
	{
		id = id || '';
		ctxt.document.write('<scr' + 'ipt id="' + id + '" type="text/javascript">\n' + jsScript + '\n<\/scr' + 'ipt>');
	}
}

WCM.LoadScript = function(src, callback)
{
    var head = document.getElementsByTagName('head')[0];
    var s = document.createElement('script');
    head.appendChild(s);

    if (WCM.IS_IE)
    {
	   s.onreadystatechange = WCM.LoadScriptCompleteIE;
    }
    else
    {
	   s.onload = WCM.LoadScriptCompleteW3C;
	   s.onerror = WCM.LoadScriptCompleteW3C;
    }

    WCM.LoadScript.callback = callback;

    s.type = 'text/javascript';
    s.src = src;
}

WCM.LoadScriptCompleteIE = function(e)
{
    var s = window.event.srcElement;
    if (s.readyState != 'loaded')
	   return;

    WCM.LoadScript.callback(s);
}

WCM.LoadScriptCompleteW3C = function(e)
{
    var s = e.currentTarget;
    WCM.LoadScript.callback(s);
}

//***************************************************************************

WCM.GetValidWindow = function(options)
{
	options = options || {};

	var ctxt = options.ctxt || window;
	var relationship = options.relationship || 'parent';
	var condition = options.condition || WCM.ReturnTrueFunction;

	var count = 0;
	var ret = null;
	var next = null;

	while (((++count) < 100) && next != ctxt[relationship] && (next = ctxt[relationship]))
	{
		try
		{
			var tmp = next.location.href;
		}
		catch(e) { break; }

		if (condition(next))
		{
			ret = ctxt = next;
		}
		else
		{
			break;
		}
	}

	return ret;
};

//***************************************************************************

WCM.GetAncestorWindow = function(options)
{
	options = options || {};
	var condition = options.condition || WCM.ReturnTrueFunction;
	var params = {w: null, condition: condition};
	var paramsId = WCM.AddObject(params);
	options.condition = $CB(WCM.GetAncestorWindow.GetValidWindowCondition, paramsId);

	WCM.GetValidWindow(options);	
	WCM.RemoveObject(paramsId);
	return params.w;
};

//***************************************************************************

WCM.GetAncestorWindow.GetValidWindowCondition = function(win, paramsId)
{
	var params = WCM.GetObject(paramsId);
	if (params && params.condition(win))
	{
		params.w = win;
		return false;
	}
	return true;
};

//***************************************************************************

WCM.GetParentWindow = function(options)
{
	options = options || {};
	options.relationship = 'parent';
	return WCM.GetAncestorWindow(options) || options.def || null;
};

//***************************************************************************

WCM.GetRootParentWindow = function(options)
{
	options = options || {};
	options.relationship = 'parent';
	return WCM.GetValidWindow(options) || options.def || null;
};

//***************************************************************************

WCM.GetOpenerWindow = function(options)
{
	options = options || {};
	options.relationship = 'opener';
	return WCM.GetAncestorWindow(options) || options.def || null;
};

//***************************************************************************

WCM.GetRootOpenerWindow = function(options)
{
	options = options || {};
	options.relationship = 'opener';
	return WCM.GetValidWindow(options) || options.def || null;
};

//***************************************************************************

WCM.GetRootWindow = function(options)
{
	options = options || {};
	options.ctxt = options.ctxt || window;
	options.def = options.ctxt;

	var count = 0;
	var next = null;

	while (((++count) < 100) && (next = WCM.GetRootOpenerWindow(WCM.GetRootWindow.GetRootWindowOptions(options))) && next != options.ctxt)
	{
		options.ctxt = next;
	}

	return options.ctxt;
};

//***************************************************************************

WCM.GetRootWindow.GetRootWindowOptions = function(options)
{
	options.ctxt = WCM.GetRootParentWindow(options);
	options.def = options.ctxt;
	return options;
};

//***************************************************************************

WCM.GetRootWcmWindow = function()
{
	return WCM.GetRootWindow({ condition: WCM.GetRootWcmWindow.Condition });
};

//***************************************************************************

WCM.GetRootWcmWindow.Condition = function(win)
{
	return (WCM.IsValidWindow(win) && WCM.IsValid(win.WCM));
};

//***************************************************************************
// Get/Set an id for any object (DOM or JS object)

WCM.GetId = function(obj)
{
	try
	{
		if (WCM.IsValid(obj) && WCM.IsString(obj.id) && obj.id.length != 0)
		{
			return obj.id;
		}
		else if (WCM.IsValid(obj))
		{
			var objId = WCM.GenerateUniqueId();
			WCM.SetId(obj, objId);
			return objId;
		}
	}
	catch(e) { }

	$D().error('Unable to get id [WCM.GetId].', window);
	return null;
};

WCM.SetId = function(obj, objId) 
{
	try
	{
		if (WCM.IsValid(obj))
		{
			obj.id = objId;
		}
	}
	catch(e) 
	{ 
		$D().error('Unable to set id [WCM.SetId].', window);
	}
};

//***************************************************************************
// Add/Get/Remove objects from the global cache

WCM.Cache = {};
WCM.Cache.Windows = {};

WCM.AddCacheObject = function(obj, objId) 
{
	objId = objId || WCM.GetId(obj);
	if (WCM.IsValidWindow(obj))
	{
		WCM.Cache.Windows[objId] = obj;
		
		try // Add window to the opener's cache
		{ window.opener.WCM.AddCacheObject(obj); } catch(e) { }
	}
	else
	{
		WCM.Cache[objId] = obj;
	}
	return objId;
};

WCM.GetCacheObject = function(objId) 
{
	return WCM.Cache[objId] || WCM.Cache.Windows[objId];
};

WCM.CleanupWindowsCache = function()
{
	var toDelete = [];
	for (var winId in WCM.Cache.Windows)	
	{
		try
		{
			if (!WCM.IsValidWindow(WCM.Cache.Windows[winId]))
			{
				toDelete.push(winId);
			}
		}
		catch(e)
		{
			toDelete.push(winId);
			delete WCM.Cache.Windows[winId];
		}
	}
	
	for (var n=0; n<toDelete.length; n++)
	{
		delete WCM.Cache.Windows[toDelete[n]];
	}
};

WCM.RemoveCacheObject = function(objId, bSetValueToNull)
{
	var obj = WCM.GetCacheObject(objId);
	if (WCM.IsValid(obj))
	{
		delete WCM.Cache[objId];
		delete WCM.Cache.Windows[objId];
		if (bSetValueToNull)
		{
			obj = null;
		}
	}
};

//***************************************************************************

WCM.IsValidWindow = function(win)
{
	try
	{		
		return (WCM.IsValid(win) && WCM.IsString(win.location.href) && WCM.IsString(win.self.location.href) && (win.location.href == win.self.location.href) && !win.closed);
	}
	catch(e)
	{
		return false;
	}
}

//***************************************************************************

WCM.GetWindowsCache = function()
{
	return WCM.Cache.Windows;
};

WCM.GetWindows = function()
{
	var collection = {};
	var collectionId = WCM.AddCacheObject(collection);
	
	// Get child contexts (frames)
	/*var root = */WCM.GetRootWindow({ condition: $CB(WCM.GetWindows.CollectWindowCondition, collectionId) });
	for (var winId in collection)
	{
		var win = collection[winId];
		if (WCM.IsValidWindow(win))
		{
			WCM.GetWindows.CollectWindows(collection[winId], collection);
		}
	}
	
	WCM.RemoveObject(collectionId);
	delete collection['id'];
	return collection;
};

WCM.GetWindows.CollectWindows = function(win, collection)
{
	if (WCM.IsValidWindow(win))
	{
		var w = null;
		WCM.GetWindows.AddContextToList(win, collection);

		if (WCM.IsValidWindow(win) && WCM.IsValid(win.WCM) && WCM.IsValid(win.WCM.Cache)  && WCM.IsValid(win.WCM.Cache.Windows) && WCM.IsValid(collection))
		{
			for (var key in win.WCM.Cache.Windows)
			{
				w = win.WCM.Cache.Windows[key];
				if (WCM.IsValidWindow(w) && !WCM.GetWindows.ExistsInCollection(w, collection))
				{
					WCM.GetWindows.CollectWindows(w, collection);
				}
			}
		}

		var frames = win.frames;
		if (frames && frames.length)
		{
			for (var n=0; n<frames.length; n++)
			{
				w = frames[n];
				if (WCM.IsValidWindow(w) && !WCM.GetWindows.ExistsInCollection(w, collection))
				{
					WCM.GetWindows.CollectWindows(w, collection);
				}
			}
		}
	}
};

WCM.GetWindows.ExistsInCollection = function(win, collection)
{
	try
	{
		return (WCM.IsValidWindow(collection[WCM.GetId(win)]));
	}
	catch(e)
	{
		return false;
	}
};

WCM.GetWindows.AddContextToList = function(win, collection)
{
	if (WCM.IsValid(collection) && WCM.IsValidWindow(win) && !WCM.GetWindows.ExistsInCollection(win, collection))
	{
		collection[WCM.GetId(win)] = win;
	}
};

WCM.GetWindows.CollectWindowCondition = function(win, collectionId)
{
	var collection = WCM.GetCacheObject(collectionId);
	if (WCM.IsValidWindow(win) && WCM.IsValid(collection))
	{
		WCM.GetWindows.AddContextToList(win, collection);
		return true;
	}
	return false;
};

//***************************************************************************

WCM.AddObject = function(obj, objId)  // Short-hand for WCM.AddCacheObject
{
	WCM.CleanupWindowsCache();
	return WCM.AddCacheObject(obj, objId);
};

WCM.RenameObjectId = function(oldId, newId) 
{
	var obj = WCM.GetObject(oldId);
	if (WCM.IsValid(obj))
	{
		WCM.SetId(obj, newId);
		WCM.AddObject(obj);
		WCM.RemoveObject(oldId);
	}
};

WCM.GetObject = function(objId, def, shallow) // Short-hand for WCM.GetCacheObject, except this method searches all global caches and window contexts for an object
{
	shallow = WCM.ToBool(shallow); // Search only adjacent contexts?
	
	//WCM.CleanupWindowsCache();

	var func = WCM.GetObject.GetObjectFromContext; 
	var obj = func(objId, window) || func(objId, window.opener) || func(objId, window.parent) || func(objId, window.top);
	if (WCM.IsValid(obj))
		return obj;
			
	if (!shallow && !WCM.IsValid(obj)) // if obj is not found, collect a list of contexts to search
	{
		$D().warn('WCM.GetObject deep search for objId: [' + objId + ']' , window);
		
		var collection = WCM.GetWindows();
	
		// Loop through collection and locate the object.
		for (var winId in collection)
		{
			obj = WCM.GetObject.LoopWindowCollection_FindObject(collection[winId], objId);
			if (WCM.IsValid(obj))
				break;
		}		
	}
	return obj || (def && WCM.GetObject(WCM.AddObject(def, objId)));
};

WCM.GetObject.LoopWindowCollection_FindObject = function(win, objId)
{
	var obj = null;
	if (WCM.IsValidWindow(win) && (obj = WCM.GetObject.GetObjectFromContext(objId, win)))
	{
		return obj;
	}
};

WCM.GetObject.GetObjectFromContext = function(objId, context)
{
	try
	{
		return (context.WCM.Cache[objId] || context.WCM.Cache.Windows[objId] || context.top.WCM.Cache[objId] || context.top.WCM.Cache.Windows[objId]);
	}
	catch (e)
	{
		return null;
	}
};

WCM.RemoveObject = function(objId, bSetValueToNull) // Short-hand for WCM.RemoveCacheObject
{
	WCM.RemoveCacheObject(objId, bSetValueToNull);
};

//***************************************************************************

WCM.EmptyFunction = function() { };
WCM.ReturnTrueFunction = function() { return true; };
WCM.ReturnFalseFunction = function() { return false; };
WCM.ReturnArrayFunction = function() { return []; };

//***************************************************************************

WCM.GetExternal = function(win)
{
	win = win || window;
	var parentObject = null;
	
	var popupId = WCM.GetQueryStringValue('WCMPopupId', win);
	if (WCM.IsValid(popupId))
	{
		parentObject = WCM.GetObject(popupId);
	}
	
	if (!WCM.IsValid(parentObject))
	{
		var isReferrerTheOpener = false;
		try
		{
			isReferrerTheOpener = (win.top.document.referrer == win.top.opener.location.href);
		}
		catch (e) { }

		if (!isReferrerTheOpener)
		{
			popupId = WCM.GetQueryStringValue('WCMPopupId', win.top.document.referrer);
			if (WCM.IsValid(popupId))
			{
				parentObject = WCM.GetObject(popupId);
			}
		}
	}

	if (!WCM.IsValid(parentObject))
	{
		$D().log($CB(WCM.GetExternal.LogWarning, WCM.AddObject(win)), window);
	}

	return parentObject;
}

//***************************************************************************

WCM.GetExternalId = function(win)
{
	return WCM.GetId(WCM.GetExternal(win));
};

//***************************************************************************

WCM.GetExternal.LogWarning = function(ctxtId)
{
	var ctxt = WCM.GetObject(ctxtId);
	return 'Window is not controlled by WCM.Popup: [' + WCM.GetUrl(ctxt) + ']';
};

//***************************************************************************

WCM.Debugger = function()
{
//	debugger;
};

//***************************************************************************
//***************************************************************************
//********************************** JSON ***********************************
//***************************************************************************
//***************************************************************************

WCM.JSON = (function () 
{
	var INDENT = "\t";
	var NEWLINE = "\n";
	var prettyPrint = false;
	var indentLevel = 0;
	var propCount = 0;
	var show = {functions: false, functionImp: false};

	var isWindow = function(x)
	{
		try { return (x && x.location && x.self && x.self.location && x.self == x); } catch(e) { return false; }
	};

	var isDomObject = function(x)
	{
		return (x && x.nodeName && x.nodeType && x.nodeType < 13);
	};

	var indent = function(a) 
	{
		if (!prettyPrint)
		{
			return a;
		}
		for (var l=0; l<indentLevel; l++) 
		{
			a[a.length] = INDENT;
		}
		return a;
	};

	var newline = function(a) 
	{
		if (prettyPrint)
		{
			a[a.length] = NEWLINE;
		}
		return a;
	};

	var m = 
	{
		'\b': '\\b',
		'\t': '\\t',
		'\n': '\\n',
		'\f': '\\f',
		'\r': '\\r',
		'"' : '\\"',
		'\\': '\\\\'
	},

	s = 
	{
		array: function (x) 
		{
			var a = ['['], b, f, i, l = x.length, v;
			a = newline(a);
			indentLevel++;
			for (i = 0; i < l; i += 1) 
			{
				v = x[i];
				f = s[typeof v];
				if (f) 
				{
					v = f(v);
					if (typeof v == 'string') 
					{
						if (b) 
						{
							a[a.length] = ',';
							a = newline(a);
						}
						a = indent(a);
						a[a.length] = v;
						b = true;
					}
				}
			}
			indentLevel--;
			a = newline(a);
			a = indent(a);			
			a[a.length] = ']';
			return a.join('');
		},

		'boolean': function (x) 
		{
			return String(x);
		},

		'null': function (x) 
		{
			return "null";
		},

		number: function (x) 
		{
			return isFinite(x) ? String(x) : 'null';
		},
		
		'function': function(x)
		{
			if (show.functions)
			{
				if (show.functionImp)
					return x.toString();
				else
					return '[function]';
			}
			else
				return null;
		},

		object: function (x) 
		{
			try
			{
				if (x) 
				{
					if (x instanceof Array) 
					{
						return s.array(x);
					}
					if (isWindow(x))
					{
						var loc = '';
						try { loc = x.location; } catch(e) { }
						return '"[window object] ' + loc + '"';
					}
					if (isDomObject(x))
					{
						return '"[dom object] ' + x.nodeName + '"';
					}
					var a = ['{'], b, f, i, v;
					a = newline(a);
					indentLevel++;
					for (i in x) 
					{
						// Removing this check for the benefit of really large static lists.
						// if (++propCount > 5000)
						// {
						// 	a = newline(a);
						// 	a[a.length] = 'Too many properties to serialize';
						// 	return a.join('');
						// }
						v = x[i];
						f = s[typeof v];
						if (f) 
						{
							v = f(v);
							if (typeof v == 'string') 
							{
								if (b) 
								{
									a[a.length] = ',';
									a = newline(a);
								}
								a = indent(a);
								a.push(s.string(i), ((prettyPrint) ? ' : ' : ':'), v);
								b = true;
							}
						}
					}
					indentLevel--;
					a = newline(a);
					a = indent(a);
					a[a.length] = '}';
					return a.join('');
				}
			}
			catch (e)
			{
				return '<assertion>'
			}
			return 'null';
		},

		string: function (x) 
		{
			if (/["\\\x00-\x1f]/.test(x)) 
			{
				x = x.replace(/([\x00-\x1f\\"])/g, function(a, b) 
				{
					var c = m[b];
					if (c) 
					{
						return c;
					}
					c = b.charCodeAt();
					return '\\u00' + Math.floor(c / 16).toString(16) + (c % 16).toString(16);
				});
			}
			if (/[\x7f-\xff]/.test(x)) 
			{
				x = x.replace(/([\x7f-\xff])/g, function(a, b) 
				{
					var c = m[b];
					if (c) 
					{
						return c;
					}
					c = b.charCodeAt();
					return '\\u00' + Math.floor(c / 16).toString(16) + (c % 16).toString(16);
				});
			}
			if (/[\u0100-\u0fff]/.test(x)) 
			{
				x = x.replace(/([\u0100-\u0fff])/g, function(a, b) 
				{
					var c = m[b];
					if (c) 
					{
						return c;
					}
					c = b.charCodeAt();
					return '\\u0' + c.toString(16);
				});
			}
			if (/[\u1000-\uffff]/.test(x)) 
			{
				x = x.replace(/([\u1000-\uffff])/g, function(a, b) 
				{
					var c = m[b];
					if (c) 
					{
						return c;
					}
					c = b.charCodeAt();
					return '\\u' + c.toString(16);
				});
			}
			return '"' + x + '"';
		}
	};

	var toJSONObject = function(s) 
	{
		try 
		{
			// Ensure the string passed in is a valid JSON string.
			return (/^[\],:{}\s]*$/.test(s.replace(/\\./g, '@').
					replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g, ']').
					replace(/(?:^|:|,)(?:\s*\[)+/g, '')) && eval('(' + s + ')'));
		} 
		catch (e) 
		{
			return false;
		}
	}

	var toJSONString = function(x, format, shw)
	{
		propCount = 0;
		indentLevel = 0;
		prettyPrint = format;
		shw = shw || {};
		show.functions = WCM.ToBool(shw.functions);
		show.functionImp = WCM.ToBool(shw.functionImp);
		return s.object(x);
	}

	var nonNativeJSONSupport = function(s, format, shw)
	{
		return WCM.IsString(s) ? toJSONObject(s) : toJSONString(s, WCM.ToBool(format), shw);
	};

	return function(s, format, shw)
	{
		if (window['JSON'] && !WCM.IsBoolean(format)) // Native JSON support?
		{
			try
			{
				return WCM.IsString(s) ? window.JSON.parse(s) : window.JSON.stringify(s);
			}
			catch (e)
			{
				return nonNativeJSONSupport(s, format, shw);
			}
		}
		else
		{
			return nonNativeJSONSupport(s, format, shw);
		}		
	}
})();

//***************************************************************************

window.$J = WCM.JSON;

//***************************************************************************
//***************************************************************************
//******************************** DEBUGGING ********************************
//***************************************************************************
//***************************************************************************

WCM.InitializeDebugMode = function()
{
	WCM.debugModeName = 'wcm.debug';

	var qs = WCM.GetQueryStringValue(WCM.debugModeName);
	var cookie = WCM.GetCookie(WCM.debugModeName);

	if (!WCM['isDebugMode'])
	{
		if (!WCM.IsNull(qs))
		{
			WCM.isDebugMode = WCM.ToBool(qs);
		}
		else if (!WCM.IsNull(cookie))
		{
			WCM.isDebugMode = WCM.ToBool(cookie);
		}
		else
			WCM.isDebugMode = false;
	}

	WCM.SetDebugMode();
}

//***************************************************************************

WCM.IsDebugMode = function()
{
	if ($D)
	{
		return WCM.ToBool(WCM['isDebugMode'], false); 
	}
	else
	{
		return false;
	}
}

//***************************************************************************

WCM.SetDebugMode = function()
{
	if (WCM.isDebugMode)
	{
		WCM.SetCookie(WCM.debugModeName, 'true');
	}
	else
	{
		WCM.RemoveCookie(WCM.debugModeName);
	}
}

//***************************************************************************
//***************************************************************************
//********************************* CONSOLE *********************************
//***************************************************************************
//***************************************************************************

WCM.Console = function(forceOpen)
{
	forceOpen = WCM.ToBool(forceOpen);

	var console = WCM.Console.GetOpenConsole();
	if (console && !console['_loaded'])
	{
		var paramsId = WCM.AddObject({console: console, forceOpen: forceOpen});

		WCM.Wait({ conditioncallback : $CB(WCM.Console.OpenConsoleWait_Condition, paramsId),
				 successcallback : $CB(WCM.Console.OpenConsoleWait_Success, paramsId),
				 errorcallback : $CB(WCM.Console.OpenConsoleWait_Error, paramsId) });
	}
	else if (console && !console.closed)
	{
		return console;
	}
	else if (forceOpen)
	{
		WCM.Console.ShowConsole();
		return WCM.Console();
	}

	return {
		log: WCM.EmptyFunction,
		todo: WCM.EmptyFunction,
		warn: WCM.EmptyFunction,
		error: WCM.Console.LogError,
		note: WCM.EmptyFunction,
		test: WCM.EmptyFunction,
		exec: WCM.EmptyFunction,
		ret: WCM.EmptyFunction,
		request: WCM.EmptyFunction,
		response: WCM.EmptyFunction,
		startProfiling: WCM.EmptyFunction,
		stopProfiling: WCM.EmptyFunction,
		setCallback: WCM.EmptyFunction,
		removeCallback: WCM.EmptyFunction,
		getCallback: WCM.Console.GetCallback,
		_log: WCM.EmptyFunction
	};
}

//***************************************************************************

WCM.Console.GetCallback = function()
{
	return WCM.EmptyFunction; 
};

//***************************************************************************

WCM.Console.ToString = function(x)
{
	if (WCM.IsString(x))
	{
		return x;
	}
	else if (WCM.IsFunction(x) || (WCM.IsValid(x) && WCM.IsValid(x.apply)))
	{
		return (x.apply(null) || '');
	}
	else
	{
		return WCM.ToString(x, '');
	}
}

//***************************************************************************

WCM.Console.LogError = function(msg, context)
{
	var errors = WCM.GetObject('wcm_errors', { id: 'wcm_errors', length: 0 });
	if (errors) 
	{
		var time = '[' + WCM.GetTime() + '] ';
		errors[errors.length++] = {msg: time + WCM.Console.ToString(msg), context: WCM.GetUrlFileName(context)};
	}
};

//***************************************************************************

WCM.Console.OpenConsoleWait_Condition = function(paramsId)
{
	var params = WCM.GetObject(paramsId);
	return (!(params.console && params.console['_loaded']));			
};

//***************************************************************************

WCM.Console.OpenConsoleWait_Success = function(paramsId)
{
	var params = WCM.GetObject(paramsId);
	WCM.RemoveObject(paramsId);
	WCM.Console(params.forceOpen);
};

//***************************************************************************

WCM.Console.OpenConsoleWait_Error = function(paramsId)
{
	var params = WCM.GetObject(paramsId);
	WCM.RemoveObject(paramsId);
	WCM.Console(params.forceOpen);
};

//***************************************************************************

window.$D = WCM.Console;

//***************************************************************************

WCM.Console.OpenConsole = function(options)
{
	options = options || {};
	var showErrors = WCM.ToBool(options.showErrors);

	var console = WCM.Console.GetOpenConsole();
	if (!console)
	{
		var context = WCM.GetRootWindow({ ctxt: window, condition: WCM.Console.OpenConsole.GetRootWindow });

		var url = context.WCM.path + 'base/wcm.console.htm?no.cache=' + WCM.GenerateUniqueId();
		WCM.Http.Send(url, $CB(WCM.Console.OpenConsole.OpenConsole, WCM.AddObject({context: context, url: url, showErrors: showErrors})), null, 'text/html');
	}
}

//***************************************************************************

WCM.Console.OpenConsole.OpenConsole = function(http, paramsId)
{
	var params = WCM.GetObject(paramsId);
	if (WCM.IsValid(params))
	{
		if (http && http.status === WCM.Http.Response.SUCCEEDED)
		{
			var text = http.GetResponseText();
			if( text.indexOf( "<!-- Site Studio Console Page -->" ) >= 0 )
			{
				var id 	 = params.context.WCM.GenerateUniqueId('log_');
				var width  = '725px';
				var height = '480px';
				var top 	 = (params.context.screenY ? params.context.screenY : params.context.screenTop) + 25 + 'px';
				var left   = (params.context.screenX ? params.context.screenX : params.context.screenLeft) + 25 + 'px';	

				var windowFeatures = 'toolbar=0,location=0,directories=0,status=0,menubar=0,scrollbars=0,resizable=1,modal=0';
				windowFeatures += ',width=' + width + ',height=' + height + ',left=' + left + ',top=' + top;

				var url = WCM.GetUrlBase(params.url) + WCM.SetQueryStringValue('show.errors', params.showErrors+'', WCM.GetQueryString(params.url));

				var win = params.context.open(url, id, windowFeatures);
				if (!win)
				{
					var key = 'wcmConsolePopupBlockerError';
					var msg = WCM.GetString(key);
					if (msg === key)
					{
						msg = 'A popup blocker may be preventing the Console window from appearing.';
					}
					params.context.alert(msg);
				}

				WCM.RemoveObject(paramsId);
				return;
			}
		}
		
		WCM.RemoveObject(paramsId);
		WCM.Console.OpenConsole.ShowErrorDlg();
	}
};

//***************************************************************************

WCM.Console.OpenConsole.ShowErrorDlg = function()
{
	if (WCM.IsValid(WCM) && WCM.IsValid(WCM.Popup))
	{
		var errors = WCM.GetObject('wcm_errors', { id: 'wcm_errors', length: 0 });
		if (errors.length !== 0)
		{
			var msgs = [];
			for (var n=0; n<errors.length; n++)
			{
				msgs.push({caption: errors[n].context, description: '<pre style="font-size:8pt">' + WCM.EscapeForPreTag(errors[n].msg) + '</pre>'});
			}

			var options = {};
			options.modal = 0;
			options.width = 640;
			options.height = 480;
			options.id = WCM.GenerateUniqueId();
			options.url = WCM.path + 'form/wcm.error.dialog.htm';

			popup = new WCM.Popup(options);
			popup.titleMsg = '';
			popup.msgs = msgs;
			popup.Open();									
		}				
	}
};

//***************************************************************************

WCM.Console.OpenConsole.GetRootWindow = function(win)
{
	return (WCM.IsValid(win['WCM']));
};

//***************************************************************************

WCM.Console.ShowConsole = function(options)
{
	var console = WCM.Console.GetOpenConsole();
	if (!console)
	{
		WCM.Console.OpenConsole(options);
	}
	else
	{
		console.focus();
	}
}

//***************************************************************************

WCM.Console.CloseConsole = function()
{
	var console = WCM.Console.GetOpenConsole();
	if (console)
	{
		console.close();
	}
}

//***************************************************************************

WCM.Console.GetOpenConsole = function()
{
	var console = WCM.GetCacheObject('console_window');
	if (console && !console.closed)
	{
		return console;
	}

	console = WCM.GetObject('console_window', null, true);
	if (console && !console.closed)
	{
		WCM.SetId(console, 'console_window');
		WCM.AddObject(console);
		return console;
	}
	
	return null;
};

//***************************************************************************

WCM.Console.ShowErrors = function()
{
	var errors = WCM.GetObject('wcm_errors', { id: 'wcm_errors', length: 0 });
	for (var n=0; n<errors.length; n++)
	{
		try
		{
			$D()._log(errors[n].msg, 'ERROR', 'error', errors[n].context);
		}
		catch(e) { }
	}
	if (errors.length === 0)
	{
		$D()._log('No errors.', 'LOG', 'log', window);
	}
	$D.ShowConsole({showErrors: true});
}

//***************************************************************************
//***************************************************************************
//******************************* INITIALIZE ********************************
//***************************************************************************
//***************************************************************************

WCM.GetResource = function(resource, def)
{
	var res = null;
	
	res = WCM.GetObject(resource, null, true);
	if (!res)
	{
		res = WCM[resource] || null;
	}
	else
	{
		res = res.res;
	}
	
	if (res)
	{
		WCM.AddObject({id: resource, res: res});
	}
	
	return (res || def);	
};

//***************************************************************************

WCM.Initialize = function()
{
	WCM.AddObject(window);

	WCM.id = WCM.GenerateUniqueId('WCM_');		 		// Unique instance id of WCM library
	$D().log(WCM.Initialize.LoadingLog(WCM.id), window);

	WCM.path = WCM.GetPathToScript(/(wcm\.js|.*composite\.js)/);

	WCM.InitializeDebugMode();				 		// Initialize Debug Namespace
	WCM.InitializeGlobalWcmVars();

	WCM.Initialize.AddEvent(window, 'load', WCM.Initialize.OnLoadHandler);
	WCM.Initialize.AddEvent(window, 'unload', WCM.Initialize.OnUnloadHandler);
	window.onerror = WCM.Initialize.OnErrorHandler;

	if (WCM.IS_IE)
	{
		// Work around the IE background image problem that floods the server with image requests when "Every time I visit the page" caching is enabled.
		try { document.execCommand("BackgroundImageCache", false, true); } catch(err) { }
	}
}

//***************************************************************************

WCM.InitializeGlobalWcmVars = function()
{
	WCM.Strings = WCM.GetResource('Strings', null);
	WCM.DefaultEditor = WCM.GetResource('DefaultEditor', null);
	WCM.SuppressAddToWebsite = WCM.GetResource('SuppressAddToWebsite', false);
	WCM.UseOnDemandEditors = WCM.GetResource('UseOnDemandEditors');
	WCM.DisableOnDemandEditorsThreshold = WCM.GetResource('DisableOnDemandEditorsThreshold');
	WCM.OnDemandEditorsThresholdCount = WCM.GetResource('OnDemandEditorsThresholdCount');
	WCM.LoadCustomElementsWithOnDemandEditors = WCM.GetResource('LoadCustomElementsWithOnDemandEditors', null);
	WCM.SuppressLargeCssOptimization = WCM.GetResource('SuppressLargeCssOptimization', false);
	WCM.UseOnDemandContributionModeMenus = WCM.GetResource('UseOnDemandContributionModeMenus', false);
	WCM.TopZIndex = WCM.GetResource('TopZIndex');
	WCM.PageDirection = WCM.GetResource('PageDirection', 'ltr');
	WCM.PageDirectionRTL = (WCM.PageDirection == 'rtl');
	WCM.InitializeRTL();
};

//***************************************************************************

WCM.Initialize.OnUnloadHandler = function()
{
	WCM.Initialize.RemoveEvent(window, 'load', WCM.Initialize.OnLoadHandler);
	WCM.Initialize.RemoveEvent(window, 'unload', WCM.Initialize.OnUnloadHandler);
	window.onerror = null;

	try
	{
		WCM.Cache.Windows = null;
		delete WCM.Cache['Windows'];
	} catch(e) { }

	try
	{
		WCM.Cache = null;
		delete WCM['Cache'];
	} catch(e) { }
	
	try
	{
		WCM.CBCache = null;
		delete WCM['CBCache'];
	} catch(e) { }
	
	try 	
	{
		window.opener.WCM.RemoveObject(window.id);
	}
	catch(e) { }
	
	if (WCM.IS_IE)
	{
		CollectGarbage();
	}
};

//***************************************************************************

WCM.Initialize.OnErrorHandler = function(msg, href, num)
{
	msg = msg || '';
	href = href || '';
	num = num || '';
	var slash = href.lastIndexOf("/");
	var file = slash == -1 ? href : href.substr(slash+1);
	$D().error(WCM.Initialize.OnErrorHandler.Log(msg, file, num), window);
	return true;
};

//***************************************************************************

WCM.Initialize.OnErrorHandler.Log = function(msg, file, num)
{
	return msg + ' - ' + file + ' (line ' + num + ')';
}

//***************************************************************************

WCM.Initialize.OnKeyDownHandler = function(e)
{
	e = e ? e : window.event; 
	if (WCM.IS_MAC && WCM.IS_FIREFOX && e.ctrlKey && e.shiftKey)
	{
		WCM.Initialize.OnKeyDownHandler.Switch.apply(null, [e.keyCode]);
	}
	else if (e.ctrlKey && e.altKey && e.shiftKey)
	{
		WCM.Initialize.OnKeyDownHandler.Switch.apply(null, [e.keyCode]);
	}
};

//***************************************************************************

WCM.Initialize.OnKeyDownHandler.Switch = function(n)
{
	switch (n || 1)
	{
		case 67/*c == 67*/: $D.ShowConsole(); break;
		case 69/*e == 69*/: $D.ShowErrors(); break;
		case 68/*d == 69*/: WCM.Debugger(); break;
	}
};

//***************************************************************************

WCM.Initialize.OnLoadHandler = function()
{
	WCM.InitializeGlobalWcmVars();
	WCM.Initialize.AddEvent(document, 'keydown', WCM.Initialize.OnKeyDownHandler);
};

//***************************************************************************

WCM.Initialize.RemoveEvent = function(elm, evType, fn)
{
	if (window.removeEventListener)
	{
		window.removeEventListener(evType, fn, false);
	}
	else if (window.detachEvent)
	{
		window.detachEvent('on' + evType, fn);
	}
	else
	{
		window['on' + evType] = null;
	}
};

//***************************************************************************

WCM.Initialize.AddEvent = function(elm, evType, fn)
{
	if (elm.addEventListener)
	{
		elm.addEventListener(evType, fn, false);
	}
	else if(elm.attachEvent)
	{
		elm.attachEvent('on' + evType, fn);
	}
	else
	{
		elm['on' + type] = fn;
	}
};

//***************************************************************************

WCM.Initialize.LoadingLog = function(libId)
{
	return 'Loading WCM library: ' + libId;
};

//***************************************************************************

WCM.InitializeRTL = function()
{
	if ((document.dir && ( document.dir.toLowerCase() == 'rtl')) ||
		(document.documentElement && document.documentElement.dir && ( document.documentElement.dir.toLowerCase() == 'rtl')) ||
	    (document.body && document.body.dir && ( document.body.dir.toLowerCase() == 'rtl')))
	{
		WCM.PageDirectionRTL = true;
	}
	else if (WCM.ToBool(WCM.PageDirectionRTL))
	{
		document.dir = WCM.PageDirection;
		document.documentElement.dir = WCM.PageDirection;
	}
}

//***************************************************************************

WCM.Initialize();

//***************************************************************************

